import colorsys
from Group import GroupBase

class AttributeGroup(GroupBase):
    _saved_attributes = ['member_values']
    def __init__(self, **kwargs):
        self.device = kwargs.get('device')
        self.member_values = {}
        self.valid = False
        signals = kwargs.get('signals_to_register', [])
        signals.append('value_changed')
        kwargs.update({'signals_to_register':signals})
        super(AttributeGroup, self).__init__(**kwargs)
        self.edited = False
        self.captured_by = None
        if self.valid:
            self.value = self.get_value_from_attributes()
        elif len(self.members) == 1:
            member = self.members[self.members.keys()[0]]
            self.value = member.value
            self.edited = member.edited
        
    def add_member(self, **kwargs):
        super(AttributeGroup, self).add_member(**kwargs)
        for key, val in kwargs.iteritems():
            self.member_values.update({key:val.value})
            #if self.device is not None:
            #    val.connect('value_changed', self.on_member_value_changed)                
        
    def del_member(self, key):
        super(AttributeGroup, self).del_member(key)
        if key in self.member_values:
            del self.member_values[key]
    
    def update_user_value(self, user=None):
        if len(self.users):
            if user:
                value = user.member_values[self.id]
                self.captured_by = user.id
                print 'group ltp=', value
            else:
                if type(self.value) == list:
                    uvals = [[u.member_values[self.id][x] for x in range(len(self.value))] for u in self.users]
                    value = [max(uval[x]) for x, uval in enumerate(uvals)]
                else:
                    value = max([u.member_values[self.id] for u in self.users])
                self.captured_by = None
                print 'group htp=', value
            self.value = value
            
    def get_values(self):
        d = {'group_value':self.value, 'member_values':{}}
        for key, val in self.members.iteritems():
            if val.captured_by != self.id:
                if getattr(val, 'base_class') == 'Group':
                    d.update({key:val.get_values()})
                else:
                    d.update({key:val.value})
        return d
        
    def get_objects(self, d={}):
        for key in ['DeviceGroup', 'AttributeGroup', 'Attribute']:
            if key not in d:
                d.update({key:{}})
        d['AttributeGroup'].update({self.id:self})
        for key, val in self.members.iteritems():
            if val.captured_by != self.id:
                if isinstance(val, AttributeGroup):
                    val.get_objects(d)
                elif val.saved_class_name == 'PatchedAttribute':
                    d['Attribute'].update({key:val})
        return d
        
    def on_member_value_changed(self, **kwargs):
        self._value = kwargs.get('value')
        print 'group member_value_changed:', self.name, self._value

class ProxyGroup(AttributeGroup):
    _saved_class_name = 'Proxy'
    def __init__(self, **kwargs):
        self._value = 0
        super(ProxyGroup, self).__init__(**kwargs)
        
    def search_for_members(self, **kwargs):
        groups = kwargs.get('groups')
        for group in groups:
            d = {group.id:group}
            self.add_member(**d)
        self.valid = True
    def add_member(self, **kwargs):
        super(ProxyGroup, self).add_member(**kwargs)
        if len(kwargs):
            uval = kwargs[kwargs.keys()[0]].value
            if type(uval) != type(self._value):
                self._value = type(uval)
                if type(uval) == list:
                    self._value = [0] * len(uval)
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, value):
        self._value = value
        for key in self.member_values.iterkeys():
            self.member_values[key] = value
        for member in self.members.itervalues():
            member.update_user_value(self)
        self.edited = True
        self.emit('value_changed', value=self.value, attribute=self)
        
class DimmerGroup(AttributeGroup):
    _saved_class_name = 'Dimmer'
    precedence_mode = 'htp'
    def __init__(self, **kwargs):
        self._value = 0
        self.color_group = None
        super(DimmerGroup, self).__init__(**kwargs)
        
    def search_for_members(self, **kwargs):
        if self.device is not None:
            found = None
            for attrib in self.device.Attributes.itervalues():
                if attrib.name == 'Dimmer':
                    found = attrib
            if found:
                self.add_member(dimmer=found)
            else:
                self.color_group = self.device.Groups.get('Color')
            self.valid = len(self.members) > 0 or self.color_group is not None
    @property
    def value(self):
        return self._value
    @value.setter
    def value(self, value):
        self._value = value
        if self.color_group is not None:
            self.color_group.set_hsv(value=value)
            #self.color_group.color = [value] * 3
        else:
            for key in self.member_values.iterkeys():
                self.member_values[key] = value
            for member in self.members.itervalues():
                member.update_user_value()
        self.edited = True
        self.emit('value_changed', value=self.value, attribute=self)
        
    def get_value_from_attributes(self):
        if self.color_group is not None:
            return self.color_group._hsv[2]
        return self.members['dimmer'].value

class ColorGroup(AttributeGroup):
    _saved_class_name = 'Color'
    color_keys = ['red', 'green', 'blue']
    hsv_keys = ['hue', 'sat', 'value']
    precedence_mode = 'ltp'
    def __init__(self, **kwargs):
        self._rgb = [0, 0, 0]
        self._hsv = [0, 0, 0]
        super(ColorGroup, self).__init__(**kwargs)
        
    def search_for_members(self, **kwargs):
        if self.device is not None:
            category = self.device.root_category.parent.subcategories['attribute'].find_category(name='Color')
            if category:
                attribs = {}
                for attrib in self.device.Attributes.itervalues():
                    if attrib in category.members and attrib.name.lower() in self.color_keys:
                        self.add_member(**{attrib.name.lower():attrib})
            self.valid = len(self.members) >= 3
    def set_hsv(self, **kwargs):
        hsv = [kwargs.get(key, self._hsv[x]) for x, key in enumerate(self.hsv_keys)]
        self.color = colorsys.hsv_to_rgb(*hsv)
    @property
    def value(self):
        return self.color
    @value.setter
    def value(self, value):
        self.color = value
    @property
    def color(self):
        return self._rgb
    @color.setter
    def color(self, value):
        self._rgb = value
        self._hsv = colorsys.rgb_to_hsv(*value)
        self.set_attributes()
        self.edited = True
        self.emit('value_changed', value=self.color, attribute=self)
        
    def get_value_from_attributes(self):
        return [self.members[key].value for key in self.color_keys]
        
    def set_attributes(self):
#        for x, val in enumerate(self._rgb):
#            attrib = self.members.get(self.color_keys[x])
#            if attrib:
#                self.member_values.update({attrib.id:val})
#                attrib.update_user_value(self)
        for key, val in self.members.iteritems():
            if isinstance(val, GroupBase):
                self.member_values.update({key:self._rgb})
            elif key in self.color_keys:
                self.member_values.update({key:self._rgb[self.color_keys.index(key)]})
            val.update_user_value(self)
        
    def on_member_value_changed(self, **kwargs):
        attrib = kwargs.get('attribute')
        value = kwargs.get('value')
        self._rgb[self.color_keys.index(attrib.name.lower())] = value
        print 'group member_value_changed:', self.name, self._value

class PositionGroup(AttributeGroup):
    _saved_class_name = 'Position'
    pos_keys = ['pan', 'tilt']
    precedence_mode = 'ltp'
    def __init__(self, **kwargs):
        self._pos = [0, 0]
        super(PositionGroup, self).__init__(**kwargs)
        
    def search_for_members(self, **kwargs):
        if self.device is not None:
            category = self.device.root_category.parent.subcategories['attribute'].find_category(name='Position')
            if category:
                attribs = {}
                for attrib in self.device.Attributes.itervalues():
                    if attrib in category.members and attrib.name.lower() in self.pos_keys:
                        self.add_member(**{attrib.name.lower():attrib})
            self.valid = len(self.members) >= 2
    @property
    def value(self):
        return self._pos
    @value.setter
    def value(self, value):
        self._pos = value
        self.set_attributes()
        self.emit('value_changed', value=self.value, attribute=self)
        
    def get_value_from_attributes(self):
        return [self.members[key].value for key in self.pos_keys]
        
    def set_attributes(self):
#        for x, val in enumerate(self._pos):
#            attrib = self.members.get(self.pos_keys[x])
#            if attrib:
#                self.member_values.update({attrib.id:val})
#                attrib.update_user_value(self)
        for key, val in self.members.iteritems():
            if isinstance(val, GroupBase):
                self.member_values.update({key:self._pos})
            elif key in self.pos_keys:
                self.member_values.update({key:self._pos[self.pos_keys.index(key)]})
            val.update_user_value(self)
            
    def on_member_value_changed(self, **kwargs):
        attrib = kwargs.get('attribute')
        value = kwargs.get('value')
        self._pos[self.pos_keys.index(attrib.name.lower())] = value

groupClasses = {}
for cls in [DimmerGroup, ColorGroup, PositionGroup, ProxyGroup]:
    groupClasses.update({cls._saved_class_name:cls})
